/**
 * @module boolean
 * @description
 * 这个模块实现了对 `TerrainSchematic` 实例进行布尔运算的功能，
 * 包括并集 (add/union)、差集 (subtract) 和交集 (intersect)。
 */

import type TerrainSchematic from "../schematic";
import { getPalette, getOrCreatePaletteIndex } from "./palette";
import { normalizeAndUpdateBounds } from "./geometry";

/**
 * 将另一个蓝图合并到当前蓝图中 (并集)。
 * @param other 要合并的另一个 TerrainSchematic 实例。
 * @param position 可选，另一个蓝图相对于当前蓝图左下角原点的放置位置。
 * @returns `this`，允许链式调用。
 */
export function add(
  schematic: TerrainSchematic,
  other: TerrainSchematic,
  position: GameVector3 = new GameVector3(0, 0, 0)
): TerrainSchematic {
  // 1. 建立 "other" 调色板到 "this" 调色板的索引映射
  const otherToThisPaletteMap = new Map<number, number>();
  const otherPalette = getPalette(other);
  for (let i = 0; i < otherPalette.length; i++) {
    const blockType = otherPalette[i];
    otherToThisPaletteMap.set(
      i,
      getOrCreatePaletteIndex(schematic, blockType.id, blockType.rot)
    );
  }

  // 2. 将当前方块放入Map中以便快速查找和覆盖
  const blocksMap = new Map<
    string,
    { x: number; y: number; z: number; p: number }
  >();
  for (const block of schematic.schematicBlocks) {
    blocksMap.set(`${block.x},${block.y},${block.z}`, block);
  }

  // 3. 遍历 "other" 的方块，添加到Map中
  for (const otherBlock of other.schematicBlocks) {
    const newBlock = {
      x: otherBlock.x + position.x,
      y: otherBlock.y + position.y,
      z: otherBlock.z + position.z,
      p: otherToThisPaletteMap.get(otherBlock.p)!,
    };
    blocksMap.set(`${newBlock.x},${newBlock.y},${newBlock.z}`, newBlock);
  }

  // 4. 从Map中重建方块列表并进行归一化
  schematic.schematicBlocks = Array.from(blocksMap.values());
  normalizeAndUpdateBounds(schematic);
  return schematic;
}

/**
 * 从当前蓝图中移除与另一个蓝图重叠的部分 (差集)。
 * @param other 要减去的另一个 TerrainSchematic 实例。
 * @param position 可选，另一个蓝图相对于当前蓝图左下角原点的放置位置。
 * @returns `this`，允许链式调用。
 */
export function subtract(
  schematic: TerrainSchematic,
  other: TerrainSchematic,
  position: GameVector3 = new GameVector3(0, 0, 0)
): TerrainSchematic {
  // 1. 创建 "other" 蓝图方块位置的哈希集合，以便快速查找
  const otherBlocksSet = new Set<string>();
  for (const otherBlock of other.schematicBlocks) {
    const key = `${otherBlock.x + position.x},${otherBlock.y + position.y},${
      otherBlock.z + position.z
    }`;
    otherBlocksSet.add(key);
  }

  // 2. 过滤当前蓝图的方块，只保留不在 "other" 集合中的方块
  schematic.schematicBlocks = schematic.schematicBlocks.filter((block) => {
    const key = `${block.x},${block.y},${block.z}`;
    return !otherBlocksSet.has(key);
  });

  // 3. 归一化并优化调色板，因为某些方块类型可能已被完全移除
  normalizeAndUpdateBounds(schematic);
  // `optimizePalette` is implicitly needed here and should be added to imports if not present
  // For now, assuming it is part of normalize or called separately.
  // Let's add it to be safe.
  // import { optimizePalette } from './palette';
  // optimizePalette(schematic);

  return schematic;
}

/**
 * 计算当前蓝图与另一个蓝图的交集，只保留两个蓝图中都存在的部分。
 * @param other 用于计算交集的另一个 TerrainSchematic 实例。
 * @param position 可选，另一个蓝图相对于当前蓝图左下角原点的放置位置。
 * @returns `this`，允许链式调用。
 */
export function intersect(
  schematic: TerrainSchematic,
  other: TerrainSchematic,
  position: GameVector3 = new GameVector3(0, 0, 0)
): TerrainSchematic {
  // 1. 创建 "other" 蓝图方块位置的哈希集合
  const otherBlocksSet = new Set<string>();
  for (const otherBlock of other.schematicBlocks) {
    const key = `${otherBlock.x + position.x},${otherBlock.y + position.y},${
      otherBlock.z + position.z
    }`;
    otherBlocksSet.add(key);
  }

  // 2. 过滤当前蓝图的方块，只保留同时存在于 "other" 集合中的方块
  schematic.schematicBlocks = schematic.schematicBlocks.filter((block) => {
    const key = `${block.x},${block.y},${block.z}`;
    return otherBlocksSet.has(key);
  });

  // 3. 归一化
  normalizeAndUpdateBounds(schematic);
  // optimizePalette(schematic);

  return schematic;
}
